#include "test_byte.h"
#include "string.h"
#include "stdlib.h"

#include "esp_timer.h"
#include "esp_log.h"
#include "esp_sleep.h"

#include "driver/gpio.h"


typedef struct {
    lua_State *L;
    const char*name;
    int funcIndex;
    int time;
    esp_timer_handle_t*handler;
}lua_user_timer;



static int lua_test_obj(lua_State *L){
    lua_user_timer**conf=(lua_user_timer**)lua_touserdata(L,1);
    if(conf==NULL){
        printf("error ...\r\n");
    }else{
        printf("ok  %d ...\r\n",(*conf)->time);
    }
    return 0;
}
// tim:start(1)执行一次
// time:start(0) 或者time:start() 重复执行
static int lua_timer_start(lua_State *L){
    int argc=lua_gettop(L);
    lua_user_timer**timer=(lua_user_timer**)lua_touserdata(L,1);
    
    if(timer==NULL||*timer==NULL||(*timer)->handler==NULL){
        luaL_error(L,"timer object is null");
        lua_pushinteger(L,0);
    }else{
        char isOnce=0;
        if(argc>1){
            isOnce=luaL_checkinteger(L,2);
        }
        if(isOnce==0){
             esp_timer_start_periodic(*((*timer)->handler), (*timer)->time);
        }else{
             esp_timer_start_once(*((*timer)->handler), (*timer)->time);
        }
       
        lua_pushinteger(L,1);
    }
    return 1;
}

// 停止
static int lua_timer_stop(lua_State *L){
    lua_user_timer**timer=(lua_user_timer**)lua_touserdata(L,1);
    if(timer==NULL||*timer==NULL||(*timer)->handler==NULL){
        luaL_error(L,"timer object is null");
        lua_pushinteger(L,0);
    }else{
        esp_timer_stop(*((*timer)->handler));
        lua_pushinteger(L,1);
    }
    return 1;
}

// 删除
static int lua_timer_delete(lua_State *L){
    lua_user_timer**timer=(lua_user_timer**)lua_touserdata(L,1);
    if(timer==NULL||*timer==NULL||(*timer)->handler==NULL){
        luaL_error(L,"timer object is null");
        lua_pushinteger(L,0);
    }else{
        esp_timer_delete(*((*timer)->handler));
        free(*timer);
        //释放内存相关的东西
        lua_pushinteger(L,1);
    }
    return 1;
}


static int lua_timer_tostring(lua_State *L){
    lua_pushstring(L,"lua Timer model");
    return 1;
}

// 执行 collectgarbage()函数会进行gc
static int lua_timer_gc(lua_State *L){
    lua_user_timer**timer=(lua_user_timer**)lua_touserdata(L,1);
    if(timer!=NULL&&*timer!=NULL){
        if((*timer)->handler!=NULL){
            esp_timer_stop(*((*timer)->handler));
            esp_timer_delete(*((*timer)->handler));
        }
        free(*timer);
    }
    return 0;
}

static const luaL_Reg lua_user_timer_func[] ={ 
    {"testObj", lua_test_obj}, 
    {"start", lua_timer_start}, 
    {"stop", lua_timer_stop}, 
    {"delete", lua_timer_delete}, 
    {"__tostring", lua_timer_tostring}, 
    {"__gc", lua_timer_gc}, 
	{NULL, NULL}
};

//定时任务回调函数
static void periodic_timer_callback(void* arg){
    //printf("call timer... \r\n");
    lua_user_timer* tm=(lua_user_timer*)arg;
    lua_State *L=tm->L;
    lua_rawgeti(L, LUA_REGISTRYINDEX, tm->funcIndex);
    lua_pushstring(L, tm->name);
    lua_pushinteger(L,tm->time);
    int r=lua_pcall(L, 2, 0,0);
    if(r>0){
        printf("err:%s\r\n",luaL_checkstring(L,-1));
    }
}

// Timer.create('time1',22,call)
static int lua_create_new_timer(lua_State *L){
     //创建一个对象指针放到stack里，返回给Lua中使用，userdata的位置-1
    
    lua_user_timer*tm=(lua_user_timer*)malloc(sizeof(lua_user_timer));

    const char*name=luaL_checkstring(L,1);
    tm->L=L;
    int ttm=luaL_checkinteger(L,2);
    tm->time=ttm;
    tm->name=name;
    int funcIndex = luaL_ref(L, LUA_REGISTRYINDEX);
    tm->funcIndex=funcIndex;


     const esp_timer_create_args_t periodic_timer_args = {
            .callback = &periodic_timer_callback,
            /* name is optional, but may help identify the timer when debugging */
            .arg = (void*) tm,
            .name = name,
    };
    esp_timer_handle_t*periodic_timer=(esp_timer_handle_t*)malloc(sizeof(esp_timer_handle_t));
    tm->handler=periodic_timer;
    ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, periodic_timer));
    printf("timer create ... \r\n");



    lua_user_timer**temp = (lua_user_timer**)lua_newuserdata(L, sizeof(lua_user_timer*));
    *temp=tm;
    //Lua->stack，得到全局元表位置-1,userdata位置-2
    luaL_getmetatable(L, "timer");
    //将元表赋值给位置-2的userdata，并弹出-1的元表
    lua_setmetatable(L, -2);
    return 1;
}

static int lua_timer_get_time(lua_State *L){
    int64_t t1 = esp_timer_get_time();
    lua_pushinteger(L,t1);
    return 1;
}

static const luaL_Reg lua_user_timer_constructor_funcs[] = {
    { "create", lua_create_new_timer },
    { "gettime", lua_timer_get_time },
    { NULL, NULL }
};

int luaopen_user_timer_libs (lua_State *L) {
     //创建全局元表（里面包含了对LUA_REGISTRYINDEX的操作），元表的位置为-1
    luaL_newmetatable(L, "timer");

    //将元表作为一个副本压栈到位置-1，原元表位置-2
    lua_pushvalue(L, -1);

    //设置-2位置元表的__index索引的值为位置-1的元表，并弹出位置-1的元表，原元表的位置为-1
    lua_setfield(L, -2, "__index");

    //将成员函数注册到元表中（到这里，全局元表的设置就全部完成了）
    luaL_setfuncs(L, lua_user_timer_func, 0);

    //注册构造函数到新表中，并返回给Lua
    luaL_newlib(L, lua_user_timer_constructor_funcs);
    return 1;
}